#pragma once

#pragma once


#define _WINSOCK_DEPRECATED_NO_WARNINGS 
#include <iostream>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>

#ifdef _WIN32
#include <windows.h>
#include <time.h>
#include <ws2tcpip.h>
#else
#include <unistd.h>
#include <arpa/inet.h>
#endif


#include "NuTradeSDK/NuStructs.h"
#include "TradeDemoSpi.h"
#include "LFDataStruct.h"
#include "sys_message.h"


struct InitData {

	static InitData & GetInstance() {
		static InitData instance;
		return instance;
	}

	void set_ctx(void * p) {
		ctx = p;
	}
	void* get_ctx() {
		return ctx;
	}

	void set_connect(bool p) {
		connect = p;
	}
	bool get_connect() {
		return connect;
	}


	void set_bev(bufferevent * p) {
		bev = p;
	}
	bufferevent* get_bev() {
		return bev;
	}

private:
	void *ctx = nullptr; // class ctx
	bool connect = false;
	struct bufferevent *bev = nullptr;

};





template<typename T>
class OrderPolicy {
public:
	static int m_request;
	static void order_logic(void * buf, void * arg) {
		T *ctx = (T *)arg;
		if (!ctx) {
			printf("ctx need init !\n");
			return;
		}
		ShareMemoryMessage *p = reinterpret_cast<ShareMemoryMessage *>  (buf);

		short msg_type = p->head.msg_type;

		switch (msg_type) {
		case MSG_TYPE_TRADE_ENGINE_LOGIN: {

			if (ctx->m_spi->m_login) {
				p->head.msg_type = MSG_TYPE_TRADE_ENGINE_OPEN;

			}
			else {
				p->head.msg_type = MSG_TYPE_TRADE_ENGINE_CLOSE;
			}

			const char *data = reinterpret_cast<const char *>(p);
			bufferevent_write(InitData::GetInstance().get_bev(), data, strlen(data) + 1);
			break;
		}

		case MSG_TYPE_LF_ORDER: {

			nusdk::OrderStockReq order;
			order.accountKey = ctx->m_spi->m_stockAccount;

			char  exchangeID[16];         ///< 市场代码
			if (p->data.lf_order.exchange == '1') {//上海
				strcpy2(order.exchangeID, "SH");
			}
			else if (p->data.lf_order.exchange == '2') {

				strcpy2(order.exchangeID, "SZ");

			}
			strcpy2(order.instrumentID, p->data.lf_order.ticker);

			if (p->data.lf_order.side == 'B') {
				order.orderType = nusdk::NU_OPT_BUY;
			}
			else {

				printf("unkknown type!\n");

			}
			order.orderVolume = p->data.lf_order.volume;
			order.priceType = nusdk::NU_PRTP_FIX;
			order.price = p->data.lf_order.price;
			strcpy2(order.remark, "net_remark");

			int rlt = ctx->m_spi->m_pApi->ReqOrderTicket(m_request++, order);
			if (rlt != 0) {
				p->head.msg_type = MSG_TYPE_ORDER_FAIL;
				const char *data = reinterpret_cast<const char *>(p);
				bufferevent_write(InitData::GetInstance().get_bev(), data, strlen(data) + 1);
			}
		}

		}
	}
};

template<typename T>
int OrderPolicy<T>::m_request = 0;


//----------------------------------------------------------------------------------------------------------------------------------
template<
	typename T,
	template<class T> class  OrderPolicy
>

class NetManager :public OrderPolicy< NetManager<T, OrderPolicy>> {

public:
	NetManager(T *spi) :m_spi(spi) {

	}

	void receive_msg_from_td(const char * msg) {

		if (!InitData::GetInstance().get_connect()) {
			printf("no connect \n");
			return;
		}
		//写数据给客户端
		printf("--------------------------------receive_msg_from_td---------------------------\n");
		int rlt = bufferevent_write(InitData::GetInstance().get_bev(), msg, strlen(msg) + 1);
		if (rlt < 0) {
			//发送异常
		}
	}


	static void cb_listener(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int len, void *ptr)
	{
		struct sockaddr_in* client = (sockaddr_in*)addr;
		cout << "connect new client: " << inet_ntoa(client->sin_addr) << "::" << ntohs(client->sin_port) << endl;

		struct event_base *base = (struct event_base*)ptr;

		//添加新事件
		struct bufferevent *bev;
		bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
		InitData::GetInstance().set_bev(bev);
		//给bufferevent缓冲区设置回调
		bufferevent_setcb(bev, read_cb, write_cb, event_cb, InitData::GetInstance().get_ctx());

		//启动 bufferevent的 读缓冲区。默认是disable 的
		bufferevent_enable(bev, EV_READ);

		InitData::GetInstance().set_connect(true);
	}


	static 	void event_cb(struct bufferevent *bev, short events, void *ctx)
	{

		if (events & BEV_EVENT_EOF)
		{
			cout << "connection closed:" << endl;
		}
		else if (events & BEV_EVENT_ERROR)
		{
			cout << "some other error !" << endl;
		}

		bufferevent_free(bev);
		cout << "bufferevent 资源已经被释放..." << endl;
	}

	void init() {

		WORD wVersionRequested;
		WSADATA wsaData;
		wVersionRequested = MAKEWORD(2, 2);
		(void)WSAStartup(wVersionRequested, &wsaData);

		//init server
		struct sockaddr_in serv;

		memset(&serv, 0, sizeof(serv));
		serv.sin_family = AF_INET;
		serv.sin_port = htons(9002);
		serv.sin_addr.s_addr = htonl(INADDR_ANY);

		//创建 event_base
		struct event_base * base;
		base = event_base_new();

		//创建套接字
		//绑定
		//接收连接请求
		struct evconnlistener* listener;
		listener = evconnlistener_new_bind(base, cb_listener, base, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 36, (struct  sockaddr*)&serv, sizeof(serv));

		//启动循环监听
		event_base_dispatch(base);
		evconnlistener_free(listener);
		event_base_free(base);

	}


	//從策略讀到數據
	static void read_cb(struct bufferevent* bev, void* arg)
	{

		char buf[1024] = { 0 };
		NetManager* ctx = (NetManager*)arg;
		bufferevent_read(bev, buf, sizeof(buf));
		order_logic(buf, ctx);
		//cout << "client " << ip << " say:" << buf << endl;

	}

	//暫時無用
	static void write_cb(struct bufferevent* bev, void* arg)
	{
		cout << "I'm 服务器，成功写数据给客户端，写缓冲回调函数被调用..." << endl;
	}

public:


	using OrderPolicy< NetManager>::order_logic;
	bufferevent* m_bev;
	T * m_spi;

};




		function<void(const char*)>  write_to_strategy_cb;



void Test5() {


	TradeDemoSpi spi;
	NetManager<TradeDemoSpi,OrderPolicy> manager(&spi);
	{
		spi.m_connPath = s_connPath;
		spi.m_logPath = s_logPath;
		spi.m_accountID = s_accountID;
		spi.m_accountType = accountType;
		spi.write_to_strategy_cb = std::bind(&NetManager<TradeDemoSpi, OrderPolicy>::receive_msg_from_td, manager, std::placeholders::_1);
	}


	//thread net(init,&spi);
	thread worker(&NetManager<TradeDemoSpi, OrderPolicy>::init, manager);
	spi.Init();
	g_ctx = &manager;
	//init(&spi); // shoud use smart ptr
	worker.detach();
	spi.InitTest();
	::Sleep(5000);

	spi.TestOrderStock();
	::Sleep(5000);

}